const gulp = require('gulp');
const babel = require('gulp-babel');
const terser = require('gulp-terser');
const less = require('less');
// const cleanCSS = require('gulp-clean-css');
const rename = require('gulp-rename');
// const concat = require('gulp-concat');
const clean = require('gulp-clean')
const ts = require('gulp-typescript');
const {
    parse,
    compileTemplate
} = require('@vue/compiler-sfc');
const through = require('through2');
const replace = require('gulp-replace');
const childProcess = require('child_process')
const path = require('path')

// TypeScript 项目
const tsProject = ts.createProject('tsconfig.json');

// 路径配置
const paths = {
    entry: 'src/index.ts',
    scripts: 'src/**/*.ts',
    styles: 'src/**/*.less',
    components: 'src/components/**/*.vue',
    dist: 'dist/',
};


gulp.task('clean', () => {
    return gulp.src(['dist'], {
            read: false,
            allowEmpty: true
        })
        .pipe(clean())
})


gulp.task('vue', () => {

    return gulp
        .src(paths.components) // 读取所有 Vue 文件
        .pipe(
            through.obj(async (file, _, cb) => {
                try {
                    const content = file.contents.toString(); // 获取文件内容
                    const {
                        descriptor
                    } = parse(content); // 解析 Vue 文件


                    // 提取 <script> 块内容
                    const scriptContent = 'const component = {};'; // 如果没有 script 块，创建一个空组件对象

                    // 提取并编译 <template> 块为 render 函数
                    let renderCode = '';
                    if (descriptor.template) {
                        const {
                            code
                        } = compileTemplate({
                            source: descriptor.template.content,
                            filename: file.path,
                            id: 'vue3-compiler', // 为模板生成唯一 ID
                        });
                        renderCode = code.replace('export ', '');
                    }

                    // 处理 <style lang="less">
                    let styleCode = '';
                    if (descriptor.styles.length > 0) {
                        for (const styleBlock of descriptor.styles) {
                            if (styleBlock.lang === 'less') {
                                const result = await less.render(styleBlock.content, {
                                    filename: file.path, // 用于解析相对路径
                                    plugins: [], // 可以扩展插件，例如 less-plugin-inline-urls
                                });
                                styleCode += result.css;
                            } else {
                                styleCode += styleBlock.content;
                            }
                        }
                    }


                    // 生成完整的组件代码
                    const finalCode = `
                    ${renderCode} // 引入渲染函数
                    ${scriptContent.replace('export default', 'const component =')}
                    if (typeof render !== 'undefined') component.render = render; // 绑定渲染函数
                    export default component; // 导出组件
                    const style = document.createElement('style');
                    style.textContent = \`${styleCode}\`;
                    document.head.appendChild(style);
                    `;

                    // 使用 gulp-replace 替换 @ 为实际路径
                    const contents = finalCode.replace(/from\s+['"](@\/.*?)['"]/g, (match, aliasPath) => {
                        // 去掉 @，然后拼接路径
                        const actualPath = path.join(__dirname, 'dist', aliasPath.replace('@', '').replace(/\//g, path.sep));
                        // 替换反斜杠为正斜杠
                        const normalizedPath = actualPath.replace(/\\/g, '/');
                        return `from '${normalizedPath}'`;
                    });




                    file.contents = Buffer.from(contents); // 替换文件内容
                    file.path = file.path.replace('.vue', '.js'); // 修改扩展名
                    cb(null, file);
                } catch (err) {
                    cb(err); // 捕获并传递错误
                }
            }),
        )
        .pipe(babel({
            presets: ['@babel/preset-env']
        })) // 转换为更兼容的 JavaScript
        .pipe(terser()) // 压缩代码
        .pipe(rename({
            extname: '.js'
        })) // 重命名为 .js 文件
        .pipe(gulp.dest(paths.dist + 'components')); // 输出到目标路径

})

// 处理 TypeScript
gulp.task('scripts', () => {
    return gulp
        .src(paths.scripts)
        .pipe(tsProject())
        .pipe(
            through.obj(function (file, enc, cb) {
                let contents = file.contents.toString();

                // 使用 gulp-replace 替换 @ 为实际路径
                contents = contents.replace(/from\s+['"](@\/.*?)['"]/g, (match, aliasPath) => {
                    // 去掉 @，然后拼接路径
                    const actualPath = path.join(__dirname, 'dist', aliasPath.replace('@', '').replace(/\//g, path.sep));
                    // 替换反斜杠为正斜杠
                    const normalizedPath = actualPath.replace(/\\/g, '/');
                    return `from '${normalizedPath}'`;
                });

                file.contents = Buffer.from(contents);
                cb(null, file);
            })
        )
        .pipe(replace(/\.vue/g, '.js')) // 替换 .vue 为 .js
        // .pipe(rename({
        //     extname: '.js'
        // })) // 修改扩展名为 .js
        .pipe(gulp.dest(paths.dist))
})

gulp.task('css', () => {
    return gulp.src(paths.styles, {
            allowEmpty: true
        })
        .pipe(gulp.dest('dist'))
})



const cmd = (cmdStr) => {
    return new Promise((resolve) => {
        childProcess.exec(cmdStr, {
            maxBuffer: 1024 * 2000
        }, function (err, stdout, stderr) {
            if (err) {
                console.log(err);
            } else if (stderr.lenght > 0) {
                console.error(stderr.join('\n'))
            } else {
                console.log(stdout);
            }

            resolve()
        });
    })
}

gulp.task('yalc:push', cb => {
    cmd('yalc push').then(() => cb())
})

// 打包任务
gulp.task('build', gulp.parallel('vue', 'scripts', 'css', ));

gulp.task('watch', () => {
    gulp.watch('src/**/*', gulp.series('clean', gulp.parallel('vue', 'scripts', 'css', ), 'yalc:push'))
})

// 默认任务
gulp.task('default', gulp.series('build'));